const http = require('http');
const mysql = require('mysql');
const axios = require('axios');
const winston = require('winston');
const prometheus = require('prom-client');
const cron = require('node-cron');
const moment = require('moment');
const LRU = require('lru-cache');

// 辅助函数：处理BIT类型的布尔值判断
function isTaskDone(doneValue) {
    if (Buffer.isBuffer(doneValue)) {
        return doneValue[0] === 1;
    }
    return doneValue === 1;
}

// 辅助函数：格式化评论内容
function formatComment(commentContent) {
    const today = moment();
    const dateStr = today.format('MMDD');
    return `${dateStr}: ${commentContent}`;
}

// 辅助函数：添加任务批注
async function addTaskComment(chatId, taskId, comment) {
    try {
        // 获取当前任务的批注
        const result = await executeDbQuery(
            'SELECT comment FROM task WHERE id = ? AND group_id = ?',
            [taskId, chatId],
            'get_task_comment'
        );

        let currentComments = '';
        if (result.length > 0 && result[0].comment) {
            currentComments = result[0].comment.trim();
            if (currentComments) currentComments += '\n';
        }

        // 追加新评论
        const newComments = currentComments + comment;

        // 更新任务批注
        await executeDbQuery(
            'UPDATE task SET comment = ?, update_time = NOW() WHERE id = ? AND group_id = ?',
            [newComments, taskId, chatId],
            'update_task_comment'
        );

        return true;
    } catch (error) {
        logger.error('添加任务批注失败', error);
        return false;
    }
}

// 辅助函数：检查是否存在循环引用
async function hasCircularReference(chatId, taskId, parentId) {
    if (taskId === parentId) return true; // 不能设置自身为父任务

    let currentParent = parentId;
    while (currentParent) {
        const result = await executeDbQuery(
            'SELECT parent_id FROM task WHERE id = ? AND group_id = ?',
            [currentParent, chatId],
            'check_circular_reference'
        );

        if (result.length === 0) break; // 父任务不存在，终止检查
        currentParent = result[0].parent_id;

        if (currentParent === taskId) {
            return true; // 发现循环引用（A → B → ... → A）
        }
    }

    return false; // 无循环引用
}

// 辅助函数：转义正则表达式特殊字符
function escapeRegExp(str) {
    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// 解析带ID和内容的指令（如 mark/edit/delay）
function parseIdAndContent(args, minParts = 2) {
    const parts = args.trim().split(/\s+/);
    if (parts.length < minParts) {
        return { error: `参数不足（至少需要${minParts}部分）` };
    }

    const idStr = parts[0];
    const id = parseInt(idStr);
    const content = parts.slice(1).join(' ').trim();

    if (isNaN(id) || id <= 0) {
        return { error: '第一个参数必须是有效的任务ID（正整数）' };
    }

    return { id, content };
}

// 解析带子命令的指令（兼容done指令的无参数场景）
function parseSubCommand(args, minParts = 2) {
    const parts = args.trim().split(/\s+/);
    // 特殊处理：done指令允许仅传入任务ID（1部分参数）
    if (minParts === 2 && parts.length === 1) {
        const id = parseInt(parts[0]);
        if (isNaN(id) || id <= 0) {
            return { error: '任务ID必须是有效的正整数' };
        }
        return { id, subCommand: null, subArgs: '' };
    }
    // 原逻辑：检查参数是否满足最小数量
    if (parts.length < minParts) {
        return { error: `参数不足（至少需要${minParts}部分）` };
    }
    const id = parseInt(parts[0]);
    const subCommand = parts[1].toLowerCase();
    const subArgs = parts.slice(2).join(' ').trim();
    if (isNaN(id) || id <= 0) {
        return { error: '任务ID必须是有效的正整数' };
    }
    return { id, subCommand, subArgs };
}

// 配置（明文形式）
const config = {
    db: {
        host: 'localhost',
        user: 'root',
        password: 'Gitee@123456',
        database: 'todo',
        port: 3306,
        connectionLimit: 20,
        connectTimeout: 10000,
        acquireTimeout: 10000,
        waitForConnections: true,
        queueLimit: 0,
        idleTimeout: 60000
    },
    feishu: {
        appId: 'cli_a763437865ff9013',
        appSecret: 'l2hxWL7oQPP5VNYYmSHTQhjPQfZkiyFf'
    },
    server: {
        port: 3000
    },
    metrics: {
        port: 9090
    }
};

// 日志系统初始化
const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        winston.format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
    ),
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'service.log' })
    ]
});

// 数据库连接池
const pool = mysql.createPool(config.db);

// 错误类型定义
class DatabaseError extends Error { constructor(msg) { super(msg); this.name = 'DatabaseError'; } }
class FeishuApiError extends Error { constructor(msg) { super(msg); this.name = 'FeishuApiError'; } }

// 数据库操作工具函数
const dbQueryDuration = new prometheus.Histogram({
    name: 'db_query_duration_seconds',
    help: '数据库查询耗时（秒）',
    labelNames: ['query_type'],
    buckets: [0.01, 0.1, 0.5, 1, 5]
});

async function executeDbQuery(query, values, queryType = 'general') {
    const start = Date.now();
    return new Promise((resolve, reject) => {
        let retries = 3;
        const attemptQuery = () => {
            pool.getConnection((err, connection) => {
                if (err) {
                    if (retries > 0) {
                        retries--;
                        logger.warn(`数据库连接失败，重试剩余${retries}次: ${err.message}`);
                        setTimeout(attemptQuery, 1000);
                        return;
                    }
                    logger.error('数据库连接失败（最大重试次数）', err);
                    return reject(new DatabaseError('数据库连接失败'));
                }
                connection.query(query, values, (error, results) => {
                    connection.release();
                    if (error) {
                        logger.error('数据库查询失败', error);
                        return reject(new DatabaseError('数据库查询失败'));
                    }
                    resolve(results);
                });
            });
        };
        attemptQuery();
    }).finally(() => {
        const duration = (Date.now() - start) / 1000;
        dbQueryDuration.labels(queryType).observe(duration);
    });
}

// 飞书API工具函数
let feishuToken = null;
let tokenExpireTime = 0;

async function refreshFeishuToken() {
    try {
        const response = await axios.post(
            'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
            { app_id: config.feishu.appId, app_secret: config.feishu.appSecret }
        );
        if (response.data.code === 0) {
            feishuToken = response.data.tenant_access_token;
            tokenExpireTime = Date.now() + (response.data.expire - 300) * 1000;  // 提前5分钟刷新
            logger.info('飞书Token刷新成功');
        }
    } catch (error) {
        logger.error('飞书Token刷新失败', error);
    }
}

async function getFeishuAppAccessToken() {
    if (feishuToken && tokenExpireTime > Date.now() + 30 * 1000) {
        return feishuToken;
    }
    await refreshFeishuToken();
    return feishuToken;
}

async function sendFeishuMessage(chatId, text) {
    const MAX_RETRIES = 3;
    let retries = 0;
    while (retries < MAX_RETRIES) {
        try {
            const accessToken = await getFeishuAppAccessToken();
            const response = await axios.post(
                'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id',
                {
                    receive_id: chatId,
                    msg_type: 'text',
                    content: JSON.stringify({ text })
                },
                {
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${accessToken}`
                    }
                }
            );
            if (response.data.code === 0) {
                logger.info(`消息发送成功（ChatID: ${chatId}）: ${text.substring(0, 50)}...`);
                return response.data;
            }
            throw new Error(`飞书消息发送失败：${response.data.msg}`);
        } catch (error) {
            retries++;
            logger.warn(`飞书消息发送失败（第${retries}次）: ${error.message}`);
            if (retries >= MAX_RETRIES) {
                logger.error('飞书消息发送达到最大重试次数', error);
                throw new FeishuApiError('飞书消息发送失败');
            }
            await new Promise(resolve => setTimeout(resolve, 1000 * retries));
        }
    }
}

// 性能监控初始化
const httpRequestCounter = new prometheus.Counter({
    name: 'http_requests_total',
    help: '总HTTP请求数',
    labelNames: ['method', 'path', 'status']
});

const httpRequestDuration = new prometheus.Histogram({
    name: 'http_request_duration_seconds',
    help: 'HTTP请求耗时（秒）',
    labelNames: ['method', 'path', 'status'],
    buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 10]
});

// grep 过滤工具函数
function handleGrepFilter(args, defaultField = 'content') {
    const grepMatch = args.match(/grep\s+(.+)/);
    if (!grepMatch) return { whereClause: '', values: [] };
    const keyword = grepMatch[1].trim();
    if (!keyword) return { whereClause: '', values: [] };
    return {
        whereClause: `${defaultField} LIKE ?`,
        values: [`%${keyword}%`]
    };
}

// 日期处理工具函数
function parseDelayDate(dateStr) {
    const today = moment();
    const targetDate = moment(dateStr, 'MMDD');
    if (targetDate.isBefore(today, 'day')) {
        return targetDate.add(1, 'years').format('YYYY-MM-DD HH:mm:ss');
    }
    return targetDate.year(today.year()).format('YYYY-MM-DD 00:00:00');
}

// ---------------------- 缓存优化核心修改 ----------------------
// 缓存初始化（延长至30分钟）
const taskCache = new LRU({
    max: 500,
    maxAge: 1000 * 60 * 30  // 30分钟
});

// 辅助函数：按chatId前缀失效所有ls缓存
function invalidateLsCache(chatId) {
    const cachePrefix = `ls:${chatId}:`;
    const allKeys = taskCache.keys();
    const keysToDelete = allKeys.filter(key => key.startsWith(cachePrefix));
    keysToDelete.forEach(key => taskCache.del(key));
    logger.info(`已失效chatId=${chatId}的ls缓存，共${keysToDelete.length}条`);
}

// ---------------------- 指令处理模块（关键修改） ----------------------
const commandHandlers = {
    async add(chatId, _, taskContent, mentions) {
        if (!taskContent) return { message: '请使用格式：add [任务内容]' };
        try {
            let parsedContent = taskContent;
            mentions.forEach(mention => {
                const openId = mention.id.open_id;
                const atTag = `<at user_id="${openId}">${mention.name}</at>`;
                parsedContent = parsedContent.replace(mention.key, atTag);
            });
            const result = await executeDbQuery(
                'INSERT INTO task (group_id, content, done, update_time) VALUES (?, ?, 0, NOW())',
                [chatId, parsedContent],
                'add_task'
            );
            invalidateLsCache(chatId);  // 替换原taskCache.del
            return { message: `任务已添加（ID: ${result.insertId}）` };
        } catch (error) {
            logger.error('添加任务失败', error);
            return { message: '添加任务失败，请稍后重试' };
        }
    },

    async ls(chatId, _, args) {
        try {
            const showAll = args.includes('-all');
            const pageMatch = args.match(/skip\s*(\d+)/);
            const page = pageMatch ? parseInt(pageMatch[1]) : 0;
            const now = moment().format('YYYY-MM-DD HH:mm:ss');
            const orderDirection = showAll ? 'DESC' : 'ASC';

            // 解析grep条件
            let grepValue = '';
            const grepMatch = args.match(/grep\s+([^-]+)/);
            if (grepMatch) {
                grepValue = grepMatch[1].trim();
            }

            // 将grep参数纳入缓存键
            const cacheKey = `ls:${chatId}:${showAll}:${page}:${grepValue}`;
            const cachedResult = taskCache.get(cacheKey);
            if (cachedResult) return { message: cachedResult };

            if (page < 0) return { message: '页码不能为负数' };

            // 构建查询条件
            const whereClauseParts = [`task.group_id = ?`];
            const whereClauseValues = [chatId];
            if (!showAll) {
                whereClauseParts.push('task.update_time < ?');
                whereClauseValues.push(now);
            }

            // 添加grep条件
            if (grepValue) {
                whereClauseParts.push('task.content LIKE ?');
                whereClauseValues.push(`%${grepValue}%`);
            }

            const whereClause = whereClauseParts.length > 0 ? `WHERE ${whereClauseParts.join(' AND ')}` : '';

            // 查询所有符合条件的任务
            const task = await executeDbQuery(`
                SELECT task.id, task.content, 
                       CAST(task.done AS UNSIGNED) AS done,
                       COALESCE(sub.subtask_count, 0) AS subtask_count,
                       COALESCE(sub.completed_subtask, 0) AS completed_subtask,
                       (COALESCE(sub.subtask_count, 0) - COALESCE(sub.completed_subtask, 0)) AS undone_subtask_count,
                       task.comment
                FROM task
                LEFT JOIN (
                    SELECT 
                        parent_id, 
                        COUNT(*) AS subtask_count,
                        SUM(CAST(done AS UNSIGNED)) AS completed_subtask
                    FROM task 
                    WHERE parent_id IS NOT NULL 
                    GROUP BY parent_id
                ) sub ON task.id = sub.parent_id
                ${whereClause}
                ORDER BY undone_subtask_count ASC, task.update_time ${orderDirection}
            `, whereClauseValues, 'list_task');

            // 根据showAll过滤结果
            const filteredtask = showAll ? task : task.filter(task => !isTaskDone(task.done));

            // 计算分页和总数
            const totalCount = filteredtask.length;
            const totalPages = Math.ceil(totalCount / 100);
            const paginatedtask = filteredtask.slice(page * 100, (page + 1) * 100);

            if (paginatedtask.length === 0) return { message: showAll ? '暂无任务' : '暂无未完成任务' };

            // 生成任务列表消息
            const taskList = paginatedtask.map(task => {
                const status = isTaskDone(task.done) ? '[已完成]' : '';
                const subtaskInfo = task.subtask_count > 0
                    ? `(${task.completed_subtask}/${task.subtask_count})`
                    : '';
                let commentInfo = '';
                if (task.comment) {
                    const comments = task.comment.split('\n').filter(c => c.trim() !== '');
                    if (comments.length > 0) {
                        commentInfo = `\n    • ${comments.join('\n    • ')}`;
                    }
                }
                return `${task.id}、${task.content} ${status} ${subtaskInfo}${commentInfo}`;
            }).join('\n');

            let message = taskList;
            if (totalPages > 1) message += `\n\n第 ${page + 1}/${totalPages} 页，共 ${totalCount} 个任务`;

            taskCache.set(cacheKey, message);
            return { message };
        } catch (error) {
            logger.error('查询任务失败', error);
            return { message: '查询任务失败，请稍后重试' };
        }
    },

    async done(chatId, _, args, mentions) {
        try {
            // 解析任务ID和子命令（兼容仅任务ID的场景）
            const parsed = parseSubCommand(args, 2);
            if (parsed.error) {
                return {
                    message: parsed.error + '\n请使用格式：\n' +
                        '- 完成任务：done [任务ID]\n' +
                        '- 完成并批注：done [任务ID] mark [批注内容]\n' +
                        '- 创建子任务：done [任务ID] need [子任务内容]\n' +
                        '- 创建父任务：done [任务ID] next [父任务内容]'
                };
            }

            const { id: taskId, subCommand, subArgs } = parsed;

            // 检查任务是否存在及所属群组
            const taskExists = await executeDbQuery(
                'SELECT id, parent_id, CAST(done AS UNSIGNED) AS done FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );

            if (taskExists.length === 0) {
                return { message: `任务#${taskId}不存在` };
            }

            const task = taskExists[0];
            let commentAdded = false;

            // 处理mark子命令（添加批注）
            if (subCommand === 'mark') {
                let commentContent = subArgs.trim();
                if (!commentContent) {
                    return { message: '请输入批注内容：done [任务ID] mark [批注]' };
                }

                // 替换@提及为飞书标签
                mentions.forEach(mention => {
                    const regex = new RegExp(escapeRegExp(mention.key), 'g');
                    commentContent = commentContent.replace(regex, `<at user_id="${mention.id.open_id}">${mention.name}</at>`);
                });

                // 格式化并添加批注
                const formattedComment = formatComment(commentContent);
                commentAdded = await addTaskComment(chatId, taskId, formattedComment);

                if (!commentAdded) {
                    return { message: '添加批注失败，请稍后重试' };
                }
            }

            // 处理need子命令（创建前置子任务）
            else if (subCommand === 'need') {
                const subtaskContent = subArgs.trim();
                if (!subtaskContent) {
                    return { message: '请输入子任务内容：done [任务ID] need [内容]' };
                }

                // 替换@提及
                let parsedContent = subtaskContent;
                mentions.forEach(mention => {
                    const regex = new RegExp(escapeRegExp(mention.key), 'g');
                    parsedContent = parsedContent.replace(regex, `<at user_id="${mention.id.open_id}">${mention.name}</at>`);
                });

                // 事务中创建子任务
                return new Promise((resolve, reject) => {
                    pool.getConnection((err, connection) => {
                        if (err) {
                            logger.error('获取数据库连接失败', err);
                            return reject(new DatabaseError('数据库连接失败'));
                        }

                        connection.beginTransaction(async (txErr) => {
                            if (txErr) {
                                connection.release();
                                return reject(new DatabaseError('事务启动失败'));
                            }

                            try {
                                // 创建子任务
                                const result = await new Promise((res, rej) => {
                                    connection.query(
                                        'INSERT INTO task (group_id, content, parent_id, done, update_time) VALUES (?, ?, ?, 0, NOW())',
                                        [chatId, parsedContent, taskId],
                                        (error, results) => error ? rej(error) : res(results)
                                    );
                                });
                                const newTaskId = result.insertId;

                                // 提交事务
                                await new Promise((res, rej) => {
                                    connection.commit(error => error ? rej(error) : res());
                                });
                                connection.release();
                                invalidateLsCache(chatId);
                                resolve({ message: `前置任务已创建（ID: ${newTaskId}）` });
                            } catch (error) {
                                connection.rollback(() => {
                                    connection.release();
                                    logger.error('事务回滚', error);
                                    reject(new DatabaseError('子任务创建失败'));
                                });
                            }
                        });
                    });
                });
            }

            // 处理next子命令（创建后续父任务）
            else if (subCommand === 'next') {
                const parentContent = subArgs.trim();
                if (!parentContent) {
                    return { message: '请输入父任务内容：done [任务ID] next [内容]' };
                }

                // 替换@提及
                let parsedContent = parentContent;
                mentions.forEach(mention => {
                    const regex = new RegExp(escapeRegExp(mention.key), 'g');
                    parsedContent = parsedContent.replace(regex, `<at user_id="${mention.id.open_id}">${mention.name}</at>`);
                });

                // 事务中创建父任务
                return new Promise((resolve, reject) => {
                    pool.getConnection((err, connection) => {
                        if (err) {
                            logger.error('获取数据库连接失败', err);
                            return reject(new DatabaseError('数据库连接失败'));
                        }

                        connection.beginTransaction(async (txErr) => {
                            if (txErr) {
                                connection.release();
                                return reject(new DatabaseError('事务启动失败'));
                            }

                            try {
                                // 创建新父任务（继承原任务的父ID）
                                const result = await new Promise((res, rej) => {
                                    connection.query(
                                        'INSERT INTO task (group_id, content, parent_id, done, update_time) VALUES (?, ?, ?, 0, NOW())',
                                        [chatId, parsedContent, task.parent_id],
                                        (error, results) => error ? rej(error) : res(results)
                                    );
                                });
                                const newTaskId = result.insertId;

                                // 将原任务设为新父任务的子任务
                                await new Promise((res, rej) => {
                                    connection.query(
                                        'UPDATE task SET parent_id = ?, update_time = NOW() WHERE id = ?',
                                        [newTaskId, taskId],
                                        error => error ? rej(error) : res()
                                    );
                                });

                                // 提交事务
                                await new Promise((res, rej) => {
                                    connection.commit(error => error ? rej(error) : res());
                                });
                                connection.release();
                                invalidateLsCache(chatId);
                                resolve({ message: `后续任务已创建（ID: ${newTaskId}）` });
                            } catch (error) {
                                connection.rollback(() => {
                                    connection.release();
                                    logger.error('事务回滚', error);
                                    reject(new DatabaseError('父任务创建失败'));
                                });
                            }
                        });
                    });
                });
            }

            // 无效子命令
            else if (subCommand) {
                return { message: `不支持的子命令：${subCommand}\n支持的子命令：mark/need/next` };
            }

            // 无subCommand时，仅标记任务为完成
            // 检查是否有未完成的子任务
            const subtaskCheck = await executeDbQuery(
                'SELECT COUNT(*) AS count FROM task WHERE parent_id = ? AND CAST(done AS UNSIGNED) = 0',
                [taskId],
                'check_subtask'
            );

            if (subtaskCheck[0].count > 0) {
                return { message: '无法完成：该任务存在未完成的子任务' };
            }

            // 标记任务为完成
            await executeDbQuery(
                'UPDATE task SET done = 1, update_time = NOW() WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'mark_task_done'
            );
            invalidateLsCache(chatId);

            // 返回结果
            return {
                message: commentAdded
                    ? `任务#${taskId}已标记为完成，并添加了批注`
                    : `任务#${taskId}已标记为完成`
            };

        } catch (error) {
            logger.error('完成任务操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },

    // 新增mark指令处理函数
    async mark(chatId, _, args, mentions) {
        try {
            // 解析任务ID和评论内容（支持空格）
            const parsed = parseIdAndContent(args);
            if (parsed.error) {
                return { message: parsed.error + '\n请使用格式：mark [任务ID] [评论内容]' };
            }

            let { id: taskId, content: commentContent } = parsed;

            // 处理@提及：全局替换所有匹配项
            mentions.forEach(mention => {
                const regex = new RegExp(escapeRegExp(mention.key), 'g');
                commentContent = commentContent.replace(regex, `<at user_id="${mention.id.open_id}">${mention.name}</at>`);
            });

            // 检查任务是否存在及所属群组
            const taskExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );
            if (taskExists.length === 0) {
                return { message: `任务#${taskId}不存在或不属于当前群组` };
            }

            // 格式化评论（添加日期前缀）
            const formattedComment = formatComment(commentContent);

            // 添加评论到数据库
            const commentAdded = await addTaskComment(chatId, taskId, formattedComment);

            if (commentAdded) {
                return { message: `已为任务#${taskId}添加批注: ${formattedComment}` };
            } else {
                return { message: '添加批注失败，请稍后重试' };
            }

        } catch (error) {
            logger.error('添加批注操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },

    async cd(chatId, _, args) {
        try {
            const taskIdStr = args.trim();
            if (taskIdStr === '/') {
                const { whereClause: grepClause, values: grepValues } = handleGrepFilter(args, 'task.content');
                const whereClauseParts = [`task.group_id = ?`, `task.parent_id IS NULL`, `CAST(task.done AS UNSIGNED) = 0`];
                const whereClauseValues = [chatId];
                if (grepClause) {
                    whereClauseParts.push(grepClause);
                    whereClauseValues.push(...grepValues);
                }
                const whereClause = whereClauseParts.length > 0 ? `WHERE ${whereClauseParts.join(' AND ')}` : '';
                const topLeveltask = await executeDbQuery(`
                    SELECT task.id, task.content, 
                           CAST(task.done AS UNSIGNED) AS done,
                           COALESCE(sub.subtask_count, 0) AS subtask_count,
                           COALESCE(sub.completed_subtask, 0) AS completed_subtask,
                           task.comment
                    FROM task
                    LEFT JOIN (
                        SELECT 
                            parent_id, 
                            COUNT(*) AS subtask_count,
                            SUM(CAST(done AS UNSIGNED)) AS completed_subtask
                        FROM task 
                        WHERE parent_id IS NOT NULL 
                        GROUP BY parent_id
                    ) sub ON task.id = sub.parent_id
                    ${whereClause}
                    ORDER BY task.update_time ASC
                `, whereClauseValues, 'list_top_task');
                if (topLeveltask.length === 0) return { message: '暂无未完成的顶级任务' };
                const taskList = topLeveltask.map(task => {
                    const status = isTaskDone(task.done) ? '[已完成]' : '';
                    const subtaskInfo = task.subtask_count > 0
                        ? `(${task.completed_subtask}/${task.subtask_count})`
                        : '';
                    let commentInfo = '';
                    if (task.comment) {
                        const comments = task.comment.split('\n').filter(c => c.trim() !== '');
                        if (comments.length > 0) {
                            commentInfo = `\n    • ${comments.join('\n    • ')}`;
                        }
                    }
                    return `${task.id}、${task.content} ${status} ${subtaskInfo}${commentInfo}`;
                }).join('\n');
                return { message: `${taskList}` };
            }
            const taskId = parseInt(taskIdStr);
            if (isNaN(taskId) || taskId <= 0) return { message: '请指定有效的任务ID（正整数）' };
            const { whereClause: grepClause, values: grepValues } = handleGrepFilter(args, 'task.content');
            const whereClauseParts = [`task.group_id = ?`, `task.parent_id = ?`];
            const whereClauseValues = [chatId, taskId];
            if (grepClause) {
                whereClauseParts.push(grepClause);
                whereClauseValues.push(...grepValues);
            }
            const whereClause = whereClauseParts.length > 0 ? `WHERE ${whereClauseParts.join(' AND ')}` : '';
            const subtask = await executeDbQuery(`
                SELECT task.id, task.content, 
                       CAST(task.done AS UNSIGNED) AS done,
                       COALESCE(sub.subtask_count, 0) AS subtask_count,
                       COALESCE(sub.completed_subtask, 0) AS completed_subtask,
                       task.comment
                FROM task
                LEFT JOIN (
                    SELECT 
                        parent_id, 
                        COUNT(*) AS subtask_count,
                        SUM(CAST(done AS UNSIGNED)) AS completed_subtask
                    FROM task 
                    WHERE parent_id IS NOT NULL 
                    GROUP BY parent_id
                ) sub ON task.id = sub.parent_id
                ${whereClause}
                ORDER BY task.update_time ASC
            `, whereClauseValues, 'list_subtask');
            if (subtask.length === 0) return { message: `任务#${taskId}没有子任务` };
            const taskList = subtask.map(task => {
                const status = isTaskDone(task.done) ? '[已完成]' : '';
                const subtaskInfo = task.subtask_count > 0
                    ? `(${task.completed_subtask}/${task.subtask_count})`
                    : '';
                let commentInfo = '';
                if (task.comment) {
                    const comments = task.comment.split('\n').filter(c => c.trim() !== '');
                    if (comments.length > 0) {
                        commentInfo = `\n    • ${comments.join('\n    • ')}`;
                    }
                }
                return `${task.id}、${task.content} ${status} ${subtaskInfo}${commentInfo}`;
            }).join('\n');
            return { message: `任务#${taskId}的子任务：\n${taskList}` };
        } catch (error) {
            logger.error('查看任务操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },

    async delay(chatId, _, args) {
        try {
            const [taskIdStr, ...dateParts] = args.split(/\s+/);
            const taskId = parseInt(taskIdStr);
            if (isNaN(taskId) || taskId <= 0) return { message: '请指定有效的任务ID（正整数）' };

            // 检查任务是否存在
            const taskExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );
            if (taskExists.length === 0) return { message: `任务#${taskId}不存在` };

            let newUpdateTime;
            if (dateParts.length === 0) {
                // 无日期参数时使用当前时间
                newUpdateTime = moment().format('YYYY-MM-DD HH:mm:ss');
            } else {
                const dateInput = dateParts[0];
                // 关键调整：先判断是否为MMDD日期格式（四位数字）
                if (/^\d{4}$/.test(dateInput)) {
                    newUpdateTime = parseDelayDate(dateInput);
                } else {
                    // 再判断是否为有效天数（-100到99之间）
                    const days = parseInt(dateInput);
                    if (!Number.isInteger(days) || days <= -100 || days >= 100) {
                        return { message: '日期格式错误，支持0-99天延期或MMDD格式（如0718）' };
                    }
                    newUpdateTime = moment().add(days, 'days').format('YYYY-MM-DD HH:mm:ss');
                }
            }

            // 执行延期操作
            await executeDbQuery(
                'UPDATE task SET update_time = ? WHERE id = ?',
                [newUpdateTime, taskId],
                'delay_task'
            );
            invalidateLsCache(chatId);  // 清除相关缓存

            // 生成结果消息（统一显示完整日期）
            const delayDate = moment(newUpdateTime).format('YYYY-MM-DD');
            if (/^\d{4}$/.test(dateParts[0])) {
                return { message: `任务#${taskId}已推迟至 ${delayDate}` };
            } else {
                const days = dateParts[0] || '0';
                return { message: `任务#${taskId}已延期${days}天，调整至 ${delayDate}` };
            }

        } catch (error) {
            logger.error('推迟任务操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },

    async edit(chatId, _, args, mentions) {
        try {
            // 解析任务ID和新内容（支持空格）
            const parsed = parseIdAndContent(args);
            if (parsed.error) {
                return { message: parsed.error + '\n请使用格式：edit [任务ID] [新任务内容]' };
            }

            let { id: taskId, content: newContent } = parsed;

            // 处理@提及：全局替换所有匹配项
            mentions.forEach(mention => {
                const regex = new RegExp(escapeRegExp(mention.key), 'g');
                newContent = newContent.replace(regex, `<at user_id="${mention.id.open_id}">${mention.name}</at>`);
            });

            // 检查任务是否存在及所属群组
            const taskExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );
            if (taskExists.length === 0) {
                return { message: `任务#${taskId}不存在或不属于当前群组` };
            }

            // 执行更新操作
            await executeDbQuery(
                'UPDATE task SET content = ?, update_time = NOW() WHERE id = ? AND group_id = ?',
                [newContent, taskId, chatId],
                'edit_task'
            );

            // 清除缓存
            invalidateLsCache(chatId);
            return { message: `任务#${taskId}已更新` };

        } catch (error) {
            logger.error('编辑任务操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },

    async drop(chatId, _, args) {
        try {
            const taskIdStr = args.trim();
            const taskId = parseInt(taskIdStr);
            if (isNaN(taskId) || taskId <= 0) {
                return { message: '请使用格式：drop [任务ID]（ID需为正整数）' };
            }

            // 检查任务是否存在且属于当前群组
            const taskExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );
            if (taskExists.length === 0) {
                return { message: `任务#${taskId}不存在或不属于当前群组` };
            }

            // 执行删除操作
            await executeDbQuery(
                'DELETE FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'delete_task'
            );

            // 清除相关缓存
            invalidateLsCache(chatId);
            return { message: `已成功删除任务#${taskId}` };

        } catch (error) {
            logger.error('删除任务失败', error);
            return { message: '删除任务失败，请稍后重试' };
        }
    },

    async make(chatId, _, args) {
        try {
            // 解析参数（格式：make [任务ID] link [父任务ID]）
            const parts = args.trim().split(/\s+/);
            if (parts.length < 3 || parts[1].toLowerCase() !== 'link') {
                return { message: '指令格式错误，请使用：make [任务ID] link [父任务ID]' };
            }

            const taskId = parseInt(parts[0]);
            const parentId = parseInt(parts[2]);

            // 验证ID有效性
            if (isNaN(taskId) || isNaN(parentId) || taskId <= 0 || parentId <= 0) {
                return { message: '任务ID和父任务ID必须为正整数' };
            }

            // 检查任务是否存在
            const taskExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [taskId, chatId],
                'check_task'
            );
            if (taskExists.length === 0) {
                return { message: `任务#${taskId}不存在或不属于当前群组` };
            }

            // 检查父任务是否存在
            const parentExists = await executeDbQuery(
                'SELECT id FROM task WHERE id = ? AND group_id = ?',
                [parentId, chatId],
                'check_parent_task'
            );
            if (parentExists.length === 0) {
                return { message: `父任务#${parentId}不存在或不属于当前群组` };
            }

            // 检查循环引用（核心调用 hasCircularReference）
            const hasCircular = await hasCircularReference(chatId, taskId, parentId);
            if (hasCircular) {
                return { message: '无法设置父任务：会导致循环引用（任务A → B → ... → A）' };
            }

            // 执行更新
            await executeDbQuery(
                'UPDATE task SET parent_id = ?, update_time = NOW() WHERE id = ? AND group_id = ?',
                [parentId, taskId, chatId],
                'set_parent_task'
            );

            // 清除缓存
            invalidateLsCache(chatId);
            return { message: `已成功设置任务#${taskId}的父任务为#${parentId}` };

        } catch (error) {
            logger.error('设置父任务操作失败', error);
            return { message: '操作失败，请稍后重试' };
        }
    },
};

// 消息去重缓存
const processedMessages = new LRU({
    max: 1000,
    maxAge: 30000  // 30秒
});

// HTTP服务器
const server = http.createServer(async (req, res) => {
    const start = Date.now();
    res.on('finish', () => {
        const duration = (Date.now() - start) / 1000;
        httpRequestDuration.labels(req.method, req.url, res.statusCode).observe(duration);
        httpRequestCounter.labels(req.method, req.url, res.statusCode).inc();
    });
    if (req.method === 'POST' && req.url === '/webhook') {
        let body = '';
        req.on('data', (chunk) => body += chunk.toString());
        req.on('end', async () => {
            try {
                const rawData = JSON.parse(body);
                let eventType = '未知';
                if (rawData.header?.event_type) eventType = rawData.header.event_type;
                else if (rawData.event?.type) eventType = rawData.event.type;
                else if (rawData.type) eventType = rawData.type;
                logger.info(`接收到飞书事件，类型: ${eventType}`);
                if (eventType === 'im.message.receive_v1' || eventType === 'message') {
                    const messageData = rawData.event?.message || rawData.message;
                    if (!messageData) {
                        logger.warn('消息数据缺失');
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        return res.end(JSON.stringify({ status: 'success', message: '忽略非消息事件' }));
                    }
                    const chatId = messageData.chat_id;
                    const messageId = messageData.message_id;
                    let messageText = '';
                    try {
                        const content = JSON.parse(messageData.content || '{}');
                        messageText = content.text || '';
                    } catch (parseError) {
                        logger.warn('解析消息内容失败', parseError);
                        messageText = '';
                    }
                    const mentions = messageData.mentions || [];
                    const now = Date.now();
                    if (processedMessages.has(messageId)) {
                        logger.info(`消息${messageId}已处理，跳过`);
                        return res.end(JSON.stringify({ status: 'success' }));
                    }
                    const trimmedText = messageText.trim();
                    const [command, ...args] = trimmedText ? trimmedText.split(/\s+/) : [];
                    const handler = commandHandlers[command?.toLowerCase()];
                    logger.info(`接收到指令: ${command}，参数: ${args.join(' ')}`);
                    if (handler) {
                        try {
                            const result = await handler(chatId, messageId, args.join(' '), mentions);
                            if (result.message) await sendFeishuMessage(chatId, result.message);
                            processedMessages.set(messageId, true);
                            res.writeHead(200, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ status: 'success' }));
                        } catch (error) {
                            logger.error(`指令${command}处理失败`, error);
                            res.writeHead(500, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ error: '服务器内部错误' }));
                        }
                    } else {
                        logger.info(`忽略不支持的指令: ${command}`);
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({ status: 'success', message: '忽略不支持的指令' }));
                    }
                } else {
                    logger.info(`忽略非消息事件: ${eventType}`);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ status: 'success', message: '忽略非消息事件' }));
                }
            } catch (error) {
                logger.error('请求处理异常', error);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: '服务器内部错误' }));
            }
        });
    } else if (req.url === '/metrics') {
        res.setHeader('Content-Type', prometheus.register.contentType);
        res.end(await prometheus.register.metrics());
    } else {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Not Found');
    }
});

// 定时任务
async function getGroupsWithUndonetask() {
    try {
        const result = await executeDbQuery(
            'SELECT DISTINCT group_id FROM task WHERE CAST(done AS UNSIGNED) = 0 AND update_time < NOW()',
            [],
            'get_groups'
        );
        return result.map(row => row.group_id);
    } catch (error) {
        logger.error('获取有未完成任务的群失败', error);
        return [];
    }
}

async function sendDailyTaskReport() {
    logger.info('启动每日任务提醒（工作日10:00）');
    try {
        const groupIds = await getGroupsWithUndonetask();
        logger.info(`发现${groupIds.length}个群有未完成任务`);
        if (groupIds.length === 0) {
            logger.info('无需要提醒的群');
            return;
        }
        const BATCH_SIZE = 5;
        for (let i = 0; i < groupIds.length; i += BATCH_SIZE) {
            const batch = groupIds.slice(i, i + BATCH_SIZE);
            await Promise.all(batch.map(async (groupId) => {
                try {
                    const lsResult = await commandHandlers.ls(groupId, `timed-${Date.now()}`, '');
                    if (lsResult.message) {
                        const reportMessage = `${lsResult.message}`;
                        await sendFeishuMessage(groupId, reportMessage);
                        logger.info(`已向群${groupId}发送提醒`);
                    }
                } catch (error) {
                    logger.error(`群${groupId}提醒失败`, error);
                }
            }));
            await new Promise(resolve => setTimeout(resolve, 500));
        }
        logger.info('每日任务提醒执行完毕');
    } catch (error) {
        logger.error('每日任务提醒失败', error);
    }
}

// 启动服务
server.listen(config.server.port, () => {
    logger.info(`服务器启动成功，监听端口${config.server.port}`);
    logger.info('定时任务已就绪：工作日上午10点发送未完成任务提醒');
    refreshFeishuToken();
    setInterval(refreshFeishuToken, 60 * 60 * 1000);
    cron.schedule('0 10 * * MON-FRI', sendDailyTaskReport);
});

// Prometheus指标服务器
const metricsServer = http.createServer(async (req, res) => {
    res.setHeader('Content-Type', prometheus.register.contentType);
    res.end(await prometheus.register.metrics());
});

metricsServer.listen(config.metrics.port, () => {
    logger.info(`Prometheus指标服务器启动，监听端口${config.metrics.port}`);
});

// 优雅关闭逻辑
function shutdown() {
    logger.info('开始优雅关闭服务...');
    server.close((err) => {
        if (err) {
            logger.error('主HTTP服务器关闭失败:', err);
        } else {
            logger.info('主HTTP服务器已关闭');
        }
        metricsServer.close((err) => {
            if (err) {
                logger.error('Prometheus指标服务器关闭失败:', err);
            } else {
                logger.info('Prometheus指标服务器已关闭');
            }
            pool.end((err) => {
                if (err) {
                    logger.error('数据库连接池关闭失败:', err);
                    process.exit(1);
                }
                logger.info('数据库连接池已关闭');
                process.exit(0);
            });
        });
    });
}

process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
process.on('uncaughtException', (error) => {
    logger.error('未捕获的异常:', error);
    shutdown();
});
process.on('unhandledRejection', (reason, promise) => {
    logger.error('未处理的 Promise 拒绝:', { reason, promise });
    shutdown();
});